//
//  BQMenuTableViewCell.m
//  BQTableViewCellDemo
//
//  Created by Zhiqiang Bao on 15-3-16.
//  Copyright (c) 2015年 Zhiqiang Bao. All rights reserved.
//

#import "BQMenuTableViewCell.h"

#define kAnimationDuration      0.2f

@interface BQMenuTableViewCell () <UIGestureRecognizerDelegate>
{
    CGFloat _maxContentXOffset;
    CGFloat _minContentXOffset;
    BOOL    _isPanning;
}

@property (nonatomic, strong) UIView *leftContainer;
@property (nonatomic, strong) UIView *rightContainer;
@property (nonatomic, assign) CGFloat startPointX;
@property (nonatomic, assign) CGFloat startFrameX;

@end

@implementation BQMenuTableViewCell

#pragma mark -

- (instancetype)init
{
    self = [super init];
    if (self) {
        [self setup];
    }
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame
{
    self = [super initWithFrame:frame];
    if (self) {
        [self setup];
    }
    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder
{
    self = [super initWithCoder:aDecoder];
    if (self) {
        [self setup];
    }
    return self;
}

- (instancetype)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier
{
    self = [super initWithStyle:style reuseIdentifier:reuseIdentifier];
    if (self) {
        [self setup];
    }
    return self;
}

- (void)setup
{
    UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(processPanGesture:)];
    panGesture.delegate = self;
    [self.contentView addGestureRecognizer:panGesture];
}

- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
    [super setSelected:selected animated:animated];
}

- (void)setHighlighted:(BOOL)highlighted animated:(BOOL)animated
{
    [super setHighlighted:highlighted animated:animated];
}

#pragma mark - UIGestureRecognizerDelegate

- (BOOL)gestureRecognizerShouldBegin:(UIPanGestureRecognizer *)gestureRecognizer
{
    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
        CGPoint point = [gestureRecognizer translationInView:self];
        return fabs(point.x) > fabs(point.y);
    }
    return YES;
}

#pragma mark -

- (void)processPanGesture:(UIPanGestureRecognizer *)pan
{
    CGPoint currentTouchPoint = [pan locationInView:self];
    
    if (pan.state == UIGestureRecognizerStateBegan) {
        self.selected = NO;
        self.startPointX = currentTouchPoint.x;
        self.startFrameX = self.contentView.frame.origin.x;
        _isPanning = YES;
    } else if (pan.state == UIGestureRecognizerStateChanged) {
        
        CGFloat deta = currentTouchPoint.x - self.startPointX + self.startFrameX;
        CGFloat wDeta = 0;
        CGFloat originX = 0;
        
        if (deta < 0) {
            if (_leftMenuStatus != BQMenuStatusHide) {
                _leftMenuStatus = BQMenuStatusHide;
                self.leftContainer.alpha = 0;
                if ([_delegate respondsToSelector:@selector(leftMenuViewHideOfCell:)]) {
                    [_delegate leftMenuViewHideOfCell:self];
                }
            }
            
            if (![_delegate respondsToSelector:@selector(rightMenuViewCountOfCell:)] ||
                [_delegate rightMenuViewCountOfCell:self] == 0) {
                deta = 0;
            } else {
                if (_rightMenuStatus == BQMenuStatusHide ) {
                    _rightMenuStatus = BQMenuStatusMoving;
                    if ([_delegate respondsToSelector:@selector(rightMenuViewShowPartlyOfCell:)]) {
                        [_delegate rightMenuViewShowPartlyOfCell:self];
                    }
                }
                
                if (deta < self.minContentXOffset) {
                    deta = (deta - self.minContentXOffset) / 2 + self.minContentXOffset;
                    wDeta = self.minContentXOffset - deta;
                }
                
                originX = deta;
                self.rightContainer.alpha = deta / (self.minContentXOffset < 0 ? self.minContentXOffset : deta);
            }
        } else {
            if (_rightMenuStatus != BQMenuStatusHide ) {
                _rightMenuStatus = BQMenuStatusHide;
                self.rightContainer.alpha = 0;
                if ([_delegate respondsToSelector:@selector(rightMenuViewHideOfCell:)]) {
                    [_delegate rightMenuViewHideOfCell:self];
                }
            }
            
            if (![_delegate respondsToSelector:@selector(leftMenuViewCountOfCell:)] ||
                [_delegate leftMenuViewCountOfCell:self] == 0) {
                deta = 0;
            } else {
                if (_leftMenuStatus == BQMenuStatusHide ) {
                    _leftMenuStatus = BQMenuStatusMoving;
                    if ([_delegate respondsToSelector:@selector(leftMenuViewShowPartlyOfCell:)]) {
                        [_delegate leftMenuViewShowPartlyOfCell:self];
                    }
                }
                
                if (deta > self.maxContentXOffset) {
                    deta =  deta - (deta - self.maxContentXOffset) / 2;
                    wDeta = deta - self.maxContentXOffset;
                    originX = self.maxContentXOffset;
                } else {
                    originX = deta;
                }
                
                self.leftContainer.alpha = deta / (self.maxContentXOffset > 0 ? self.maxContentXOffset : deta);
            }
        }
        
        CGRect frame = self.contentView.frame;
        frame.origin.x = originX;
        frame.size.width = self.frame.size.width + wDeta;
        self.contentView.frame = frame;
        
    } else if (pan.state == UIGestureRecognizerStateEnded) {
        
        CGFloat deta = currentTouchPoint.x - self.startPointX + self.startFrameX;
        
        if (deta < self.minContentXOffset / 2) {
            [self openRightMenu];
        } else if (deta > self.maxContentXOffset / 2) {
            [self openLeftMenu];
        } else {
            [self hideLeftMenu];
            [self hideRightMenu];
        }
        
        _isPanning = NO;
    }
}

- (NSUInteger)indexOfTap:(UITapGestureRecognizer *)tap inView:(UIView *)view
{
    NSUInteger index = -1;
    CGFloat count = view.subviews.count;
    if (count > 0) {
        CGFloat width = view.frame.size.width / count;
        if (width > 0) {
            CGPoint point = [tap locationInView:view];
            CGFloat x = MAX(point.x, 0);
            index = MIN(x / width, count - 1);
        }
    }
    return index;
}

- (void)processLeftTapGesture:(UITapGestureRecognizer *)tap
{
    NSUInteger index = [self indexOfTap:tap inView:self.leftContainer];
    
    if (index != -1) {
        if ([_delegate respondsToSelector:@selector(leftMenuView:didSelectAtIndex:)]) {
            [_delegate leftMenuView:self didSelectAtIndex:index];
        }
    }
}

- (void)processRightTapGesture:(UITapGestureRecognizer *)tap
{
    NSUInteger index = [self indexOfTap:tap inView:self.rightContainer];
    
    if (index != -1) {
        if ([_delegate respondsToSelector:@selector(rightMenuView:didSelectAtIndex:)]) {
            [_delegate rightMenuView:self didSelectAtIndex:index];
        }
    }
}

- (void)updateContentView
{
    CGRect frame = self.contentView.frame;
    
    if (self.leftMenuStatus == BQMenuStatusShow) {
        frame.origin.x = self.leftContainer.frame.size.width;
        frame.size.width = self.frame.size.width - (self.leftContainer.frame.size.width - self.maxContentXOffset);
    } else if (self.rightMenuStatus == BQMenuStatusShow) {
        frame.origin.x = self.minContentXOffset;
        frame.size.width = self.frame.size.width - (self.rightContainer.frame.size.width + self.minContentXOffset);
    }
    
    self.contentView.frame = frame;
}

- (void)updateLeftContainer
{
    NSUInteger count = 0;
    if ([_delegate respondsToSelector:@selector(leftMenuViewCountOfCell:)]) {
        count = [_delegate leftMenuViewCountOfCell:self];
    }
    
    [self.leftContainer removeFromSuperview];
    self.leftContainer = [[UIView alloc] init];
    self.leftContainer.alpha = (_leftMenuStatus == BQMenuStatusHide) ? 0 : 1;
    
    if (_leftMenuPriority == BQMenuPriorityBelowContent) {
        [self insertSubview:self.leftContainer belowSubview:self.contentView];
    } else {
        [self insertSubview:self.leftContainer aboveSubview:self.contentView];
    }
    
    CGFloat x = 0, h = self.contentView.frame.size.height;
    for (NSUInteger i = 0; i < count; i++) {
        UIView *view = nil;
        if ([_delegate respondsToSelector:@selector(leftMenuViewAtIndex:ofCell:)]) {
            view = [_delegate leftMenuViewAtIndex:i ofCell:self];
        }
        CGFloat width = view.frame.size.width;
        if ([_delegate respondsToSelector:@selector(leftMenuViewWidthAtIndex:ofCell:)]) {
            width = [_delegate leftMenuViewWidthAtIndex:i ofCell:self];
        }
        view.frame = CGRectMake(x, 0, width, h);
        
        if (view) {
            [self.leftContainer addSubview:view];
        }
        
        x += width;
    }
    
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(processLeftTapGesture:)];
    tap.delegate = self;
    [self.leftContainer addGestureRecognizer:tap];
    self.leftContainer.frame = CGRectMake(0, 0, x, h);
}

- (void)updateRightContainer
{
    NSUInteger count = 0;
    if ([_delegate respondsToSelector:@selector(rightMenuViewCountOfCell:)]) {
        count = [_delegate rightMenuViewCountOfCell:self];
    }
    
    [self.rightContainer removeFromSuperview];
    self.rightContainer = [[UIView alloc] init];
    self.rightContainer.alpha = (_rightMenuStatus == BQMenuStatusHide) ? 0 : 1;
    
    if (_rightMenuPriority == BQMenuPriorityBelowContent) {
        [self insertSubview:self.rightContainer belowSubview:self.contentView];
    } else {
        [self insertSubview:self.rightContainer aboveSubview:self.contentView];
    }
    
    CGFloat x = 0, h = self.contentView.frame.size.height;
    for (NSUInteger i = 0; i < count; i++) {
        UIView *view = nil;
        if ([_delegate respondsToSelector:@selector(rightMenuViewAtIndex:ofCell:)]) {
            view = [_delegate rightMenuViewAtIndex:i ofCell:self];
        }
        CGFloat width = view.frame.size.width;
        if ([_delegate respondsToSelector:@selector(rightMenuViewWidthAtIndex:ofCell:)]) {
            width = [_delegate rightMenuViewWidthAtIndex:i ofCell:self];
        }
        view.frame = CGRectMake(x, 0, width, h);
        
        if (view) {
            [self.rightContainer addSubview:view];
        }
        
        x += width;
    }
    
    UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(processRightTapGesture:)];
    tap.delegate = self;
    [self.rightContainer addGestureRecognizer:tap];
    self.rightContainer.frame = CGRectMake(self.frame.size.width - x, 0, x, h);
}

- (void)layoutSubviews
{
    if (_isPanning) return;
    
    [super layoutSubviews];
    
    [self updateLeftContainer];
    [self updateRightContainer];
    [self updateContentView];
}

#pragma mark - api

- (void)openLeftMenu
{
    BQMenuStatus status = _leftMenuStatus;
    
    [self hideRightMenu];
    
    if (_leftMenuStatus == BQMenuStatusHide ) {
        if ([_delegate respondsToSelector:@selector(leftMenuViewShowPartlyOfCell:)]) {
            [_delegate leftMenuViewShowPartlyOfCell:self];
        }
    }
    
    [UIView animateWithDuration:kAnimationDuration delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
        CGRect frame = self.contentView.frame;
        frame.origin.x = self.leftContainer.frame.size.width;
        frame.size.width = self.frame.size.width - (self.leftContainer.frame.size.width - self.maxContentXOffset);
        self.contentView.frame = frame;
        self.leftContainer.alpha = 1;
        _leftMenuStatus = BQMenuStatusShow;
    } completion:^(BOOL finished) {
        if (status != BQMenuStatusShow) {
            if ([_delegate respondsToSelector:@selector(leftMenuViewShowCompeletelyOfCell:)]) {
                [_delegate leftMenuViewShowCompeletelyOfCell:self];
            }
        }
    }];
}

- (void)hideLeftMenu
{
    if (_leftMenuStatus == BQMenuStatusHide) return;
    _leftMenuStatus = BQMenuStatusHide;
    
    [UIView animateWithDuration:kAnimationDuration delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
        CGRect frame = self.contentView.frame;
        frame.origin.x = 0;
        frame.size.width = self.frame.size.width;
        self.contentView.frame = frame;
        self.leftContainer.alpha = 0;
    } completion:^(BOOL finished) {
        if ([_delegate respondsToSelector:@selector(leftMenuViewHideOfCell:)]) {
            [_delegate leftMenuViewHideOfCell:self];
        }
    }];
}

- (void)openRightMenu
{
    BQMenuStatus status = _rightMenuStatus;
    
    [self hideLeftMenu];
    
    if (_rightMenuStatus == BQMenuStatusHide ) {
        if ([_delegate respondsToSelector:@selector(rightMenuViewShowPartlyOfCell:)]) {
            [_delegate rightMenuViewShowPartlyOfCell:self];
        }
    }
    
    [UIView animateWithDuration:kAnimationDuration delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
        CGRect frame = self.contentView.frame;
        frame.origin.x = self.minContentXOffset;
        frame.size.width = self.frame.size.width - (self.rightContainer.frame.size.width + self.minContentXOffset);
        self.contentView.frame = frame;
        self.rightContainer.alpha = 1;
        _rightMenuStatus = BQMenuStatusShow;
    } completion:^(BOOL finished) {
        if (status != BQMenuStatusShow) {
            if ([_delegate respondsToSelector:@selector(rightMenuViewShowCompeletelyOfCell:)]) {
                [_delegate rightMenuViewShowCompeletelyOfCell:self];
            }
        }
    }];
}

- (void)hideRightMenu
{
    if (_rightMenuStatus == BQMenuStatusHide) return;
    _rightMenuStatus = BQMenuStatusHide;
    
    [UIView animateWithDuration:kAnimationDuration delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^{
        CGRect frame = self.contentView.frame;
        frame.origin.x = 0;
        frame.size.width = self.frame.size.width;
        self.contentView.frame = frame;
        self.rightContainer.alpha = 0;
    } completion:^(BOOL finished) {
        if ([_delegate respondsToSelector:@selector(rightMenuViewHideOfCell:)]) {
            [_delegate rightMenuViewHideOfCell:self];
        }
    }];
}

- (void)reloadMenuData
{
    [self layoutIfNeeded];
}

#pragma mark -

- (void)setMaxContentXOffset:(CGFloat)maxContentXOffset
{
    _maxContentXOffset = MAX(maxContentXOffset, 0);
}

- (void)setMinContentXOffset:(CGFloat)minContentXOffset
{
    _minContentXOffset = MIN(minContentXOffset, 0);
}

- (CGFloat)maxContentXOffset
{
    if (_maxContentXOffset == 0) {
        return self.leftContainer.frame.size.width;
    }
    return _maxContentXOffset;
}

- (CGFloat)minContentXOffset
{
    if (_minContentXOffset == 0) {
        return -self.rightContainer.frame.size.width;
    }
    return _minContentXOffset;
}

@end
